// 因为所有的class最终都继承自Object，而Object定义了几个重要的方法：
// toString()：把instance输出为String；
// equals()：判断两个instance是否逻辑相等；
// hashCode()：计算一个instance的哈希值。

// final修饰的类不能被继承
class Person {
    // 用final修饰的字段在初始化后不能被修改。例如：
    final int age = 18;
    // final字段必须在声明时或在构造方法中初始化
    final String name;

    Person(String name) {
        this.name = name; // 构造方法中初始化
        // this.age = 20; // 初始化已经完成，不能再修改
    }

    public void run() {
        System.out.println("Person.run");
    }

    // final修饰的方法不能被Override
    public final void walk() {
        System.out.println("Person.walk");
    }
}

class Student extends Person {
    Student() {
        super("Student");
    }

    // 重写父类方法: @Override可以让编译器帮助检查是否进行了正确的覆写
    @Override
    public void run() {
        System.out.println("Student.run");
    }
    // 无法Override final修饰的方法
    // @Override
    // public void walk() {
    // System.out.println("Student.walk");
    // }
}

public class Test {
    public static void main(String[] args) {
        Person p = new Person("Person");
        p.run();
        p = new Student(); // 子类对象赋值给父类引用
        p.run(); // Java的实例方法调用是基于运行时的实际类型的动态调用，而非变量的声明类型
    }
}